/*
 * =====================================================================================
 *
 *       Filename:  tcpConnection.c
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  07/13/2012 03:01:37 PM
 *       Revision:  none
 *       Compiler:  gcc/g++
 *
 *         Author:  wangtengchao , wangtengchao AT gmail.com
 *   Organization:  
 *
 * =====================================================================================
 */

#include"tcpConnect.h"
#include "defines.h"
#include "eventHandler.h"
#include"demultiplexer.h"
#include "dispatcher.h"
#include "netHelp.h"
#include "netBuffer.h"
#include <boost/enable_shared_from_this.hpp>
#include <boost/bind.hpp>
#ifdef NET_DEBUG
#include <cstdio>

#endif
using namespace inm::net;
TcpConnect::TcpConnect(const std::string &name, Dispatcher *dispatcher, int sockfd, const InetAddr &localAddr, const InetAddr &peerAddr)
    : EventHandler(name,dispatcher),
      socket_(sockfd),
      localAddr_(localAddr),
      peerAddr_(peerAddr),
      hasMoreToWrite(false)
{

}

TcpConnect::~TcpConnect()
{
#ifdef NET_DEBUG
    printf("~TcpConnect\n");
#endif
}

void TcpConnect::sendMessage(const char* msg,size_t num)
{//write

#ifdef NET_DEBUG
    printf("sendMessage\n");
#endif
    ssize_t remains = static_cast<ssize_t>(num);
	ssize_t writeNum = 0;
    if(!hasMoreToWrite)//if have write operation in tasks.then also need  to add tasks
    {//write immediately
        writeNum = inm::net::Write(socket_.getSockFd(),msg,num);
        if(writeNum >= 0)//for if write return -1 ,we should not -writeNum
            remains -= writeNum;
    }
    assert(remains <= num);

    if(remains > 0)
    {//register WRITE_EVENT
        //attention:  write complete
		outputBuffer_.append(msg+writeNum,remains);
        hasMoreToWrite = true;
        dispatcher_->addToTasks(boost::bind(&Dispatcher::updateHandler,
                                            dispatcher_,
                                            shared_from_this(),
                                            EVENT_ADD,
                                            WRITE_EVENT));
    }
    if(remains == 0 && writeComleteCallback_)
        dispatcher_->addToTasks(boost::bind(&TcpConnect::writeComplete,shared_from_this()));

}



void TcpConnect::handleRead()
{
#ifdef NET_DEBUG
    printf("tcpconnect::handleRead\n");
#endif
    Timestamp t = Timestamp::now();
    size_t _size = inputBuffer_.readFromFd(socket_.getSockFd());
    if(_size > 0 && messageCallback_)
        messageCallback_(shared_from_this(),&inputBuffer_,t);
    else
        if(_size == 0)//close and close operation can be done after poll so put into tasks
            dispatcher_->addToTasks(boost::bind(&TcpConnect::handleClose,shared_from_this()));

}
void TcpConnect::handleWrite()
{//处理一次没写完的情况
#ifdef NET_DEBUG
    printf("tcpconnect::handleWrite\n");
#endif
    if(outputBuffer_.readableNum() >0)
        sendMessage(outputBuffer_.peek(),outputBuffer_.getBufferSize());
    if(outputBuffer_.readableNum() == 0)
    {//outbuffer send complete
        hasMoreToWrite = false;

        dispatcher_->addToTasks(boost::bind(&Dispatcher::updateHandler,
                                            dispatcher_,
                                            shared_from_this(),
                                            EVENT_DEL,
                                            WRITE_EVENT));

    }
}
void TcpConnect::handleClose()
{//1.取消dispatcher中的注册   2.关闭连接
#ifdef NET_DEBUG
    printf("tcpconnect::handleClose\n");
#endif
    dispatcher_->removeHandler(shared_from_this(),ALL_EVENT);


}

void TcpConnect::connectEstablished()
{//used when new TcpConnection put into dispatcher
#ifdef NET_DEBUG
    printf("tcpconnect::connectEstablist\n");
#endif

    dispatcher_->registerHandler(shared_from_this(),READ_EVENT);
    if(connectCallback_)
        connectCallback_(shared_from_this());
}
void TcpConnect::writeComplete()
{
    if(writeComleteCallback_)
        writeComleteCallback_(shared_from_this());
}
void TcpConnect::setNoDelay(bool b)
{
	socket_.setNoDelay(b);	
}
